package modelo;

import java.util.ArrayList;
import java.util.Iterator;

import excepcion.ErrorPosicionFueraDeRango;

public abstract class Nave {
	
	private Movimiento movimiento;
	protected ArrayList<BloqueDeNave> partes = new ArrayList<>();
	private String orientacion;
	
	Nave(String direccion, String orientacion, Posicion posIni) {
		this.movimiento = new Movimiento(direccion);
		this.orientacion = orientacion;
		
		this.cargarPartes(posIni, orientacion);

	}
	
	protected abstract int devolverTamanio();
	
	public void cargarPartes(Posicion posIni, String orientacion) {
		this.partes.add(new BloqueDeNave(posIni,resistenciaPorBloque()));
		
		// devolverTamanio es metodo abstracto, lo ejecuta cada clase concreta;
		int tope = this.devolverTamanio();
		
		Posicion posActual = posIni;
		
		for (int i=1; i<tope; i++){
			Posicion nuevaPosicion = null;
			
			switch(orientacion) {
				case "este": {
					try {
						nuevaPosicion = posActual.siguienteColumna(1);
					}
					catch (ErrorPosicionFueraDeRango e1){
						this.partes.clear();
						this.orientacion = "oeste";
						this.cargarPartes(posIni,"oeste");
					}
				break;
				}
				
				case "oeste": {
					try{
						nuevaPosicion = posActual.siguienteColumna(-1);
					}
					catch (ErrorPosicionFueraDeRango e2){
						this.partes.clear();
						this.orientacion = "este";
						this.cargarPartes(posIni,"este");
					}
				break;
				}
				
				case "norte": {
					try{
						nuevaPosicion = posActual.siguienteFila(-1);
					}
					catch (ErrorPosicionFueraDeRango e3){
						this.partes.clear();
						this.orientacion = "sur";
						this.cargarPartes(posIni,"sur");
					}
				break;	
				}
				
				case "sur": {
					try{
						nuevaPosicion = posActual.siguienteFila(1);
					}
					catch (ErrorPosicionFueraDeRango e4){
						this.partes.clear();
						this.orientacion = "norte";
						this.cargarPartes(posIni,"norte");
					}
				break;
				}
				
				
			}
			if (nuevaPosicion != null ){
				BloqueDeNave unBloque = new BloqueDeNave(nuevaPosicion,resistenciaPorBloque());
				if (i==(tope-1)){
					unBloque.ingresarParte("proa");
				}
				else{
					unBloque.ingresarParte("medio");
				}
									
				posActual = nuevaPosicion;
				this.partes.add(unBloque);

			}
		}
	}
	
	
	abstract int resistenciaPorBloque();
	
	void invertirMovimiento() {
		movimiento.invertirMovimiento();

	}
	
	public void moverNave() {
		
		ArrayList<Posicion> listaPosAux = new ArrayList<Posicion> ();
		boolean modificar = false;
		Iterator<BloqueDeNave> iterador = partes.iterator();

		
		for(BloqueDeNave bloque: partes) {
			Posicion posAuxiliar = movimiento.mover(bloque.getPosicion());
			listaPosAux.add(bloque.getPosicion());
			modificar = (posAuxiliar == bloque.getPosicion());
			if (modificar)
				break;
			bloque.setPosicion(posAuxiliar);
		}
		
		if (modificar){
			for (Posicion unaPosicion:listaPosAux)
				 iterador.next().setPosicion(unaPosicion);
		}		
	}
	
	public void recibirDisparo(Posicion posicion) {
		for(BloqueDeNave bloque: partes) {
			if (bloque.getPosicion().equals(posicion)) {
				bloque.recibeDanio();
			}
		}
	}
	
	public void recibirExplosion(Mina mina) {
		OndaExpansiva ondaExpansiva = mina.obtenerOndaExpansiva();
		for(BloqueDeNave bloque: partes) {
			if (ondaExpansiva.destruyePosicion(bloque.getPosicion())) {
				bloque.recibeDanio();
			}
		}
	}
	
	public boolean destruida() {
		boolean destruida = true;
		
		for(BloqueDeNave bloque: partes) {
			if (!bloque.destruido()) {
				destruida = false;
			}
		}
		return destruida;
	}

	public boolean navegaEn(Posicion posicion) {
		boolean encontrado = false;
		
		for(BloqueDeNave bloque: partes) {
			if ((bloque.getPosicion()).equals(posicion)) {
				encontrado = true;
			}
		}
		return encontrado;
	}

	public String obtenerOrientacion() {
		return orientacion;
	}

	public void ingresarOrientacion(String orientacion) {
		this.orientacion = orientacion;
	}
	
	public String obtenerDireccion(){
		return this.movimiento.obtenerDireccion();
	}
	
	public ArrayList<BloqueDeNave> obtenerPartes(){
		return this.partes;
	}
	
}
